using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
using Matrix.Configuration.Events;
using Matrix.Configuration.Services;

namespace Matrix.Application.Services
{
    /// <summary>
    /// 事件持久化服务实现
    /// 负责事件的持久化存储和查询
    /// 简化实现：使用分布式缓存作为存储，生产环境建议使用数据库
    /// </summary>
    public class EventPersistenceService : IEventPersistenceService, ITransientDependency
    {
        private readonly ILogger<EventPersistenceService> _logger;
        private readonly IDistributedCache _distributedCache;
        private readonly IClock _clock;
        private readonly IOptions<ConfigurationEventOptions> _options;

        private const string EventPrefix = "config_event:";
        private const string BatchEventPrefix = "config_batch_event:";
        private const string HistoryPrefix = "config_event_history:";
        private const string StatisticsPrefix = "config_event_stats:";

        public EventPersistenceService(
            ILogger<EventPersistenceService> logger,
            IDistributedCache distributedCache,
            IClock clock,
            IOptions<ConfigurationEventOptions> options)
        {
            _logger = logger;
            _distributedCache = distributedCache;
            _clock = clock;
            _options = options;
        }

        public async Task PersistEventAsync(ConfigurationChangedEto eventData)
        {
            if (eventData == null)
            {
                throw new ArgumentNullException(nameof(eventData));
            }

            try
            {
                var cacheKey = GetEventCacheKey(eventData.EventId);
                var eventDataJson = System.Text.Json.JsonSerializer.Serialize(eventData);
                var expiration = TimeSpan.FromDays(_options.Value.MaxEventRetentionDays);
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration };

                await _distributedCache.SetStringAsync(cacheKey, eventDataJson, options);

                // 添加到历史记录
                await AddToHistoryAsync(eventData);

                // 更新统计信息
                await UpdateStatisticsAsync(eventData);

                _logger.LogDebug("配置变更事件已持久化: EventId: {EventId}, Key: {Key}",
                    eventData.EventId, eventData.Key);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "持久化配置变更事件失败: EventId: {EventId}", eventData.EventId);
                // 持久化失败不应该影响主流程
            }
        }

        public async Task PersistBatchEventAsync(ConfigurationBatchChangedEto batchEventData)
        {
            if (batchEventData == null)
            {
                throw new ArgumentNullException(nameof(batchEventData));
            }

            try
            {
                var cacheKey = GetBatchEventCacheKey(batchEventData.BatchEventId);
                var batchEventDataJson = System.Text.Json.JsonSerializer.Serialize(batchEventData);
                var expiration = TimeSpan.FromDays(_options.Value.MaxEventRetentionDays);
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration };

                await _distributedCache.SetStringAsync(cacheKey, batchEventDataJson, options);

                // 为每个子事件添加到历史记录
                foreach (var eventData in batchEventData.Changes)
                {
                    await AddToHistoryAsync(eventData);
                    await UpdateStatisticsAsync(eventData);
                }

                _logger.LogDebug("批量配置变更事件已持久化: BatchEventId: {BatchEventId}, Changes: {ChangeCount}",
                    batchEventData.BatchEventId, batchEventData.Changes.Count);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "持久化批量配置变更事件失败: BatchEventId: {BatchEventId}",
                    batchEventData.BatchEventId);
                // 持久化失败不应该影响主流程
            }
        }

        public async Task<List<ConfigurationChangedEto>> GetChangeHistoryAsync(
            string key,
            string @namespace = "",
            int maxCount = 50,
            Guid? tenantId = null)
        {
            try
            {
                var historyKey = GetHistoryCacheKey(key, @namespace, tenantId);
                var historyJson = await _distributedCache.GetStringAsync(historyKey);

                if (string.IsNullOrEmpty(historyJson))
                {
                    return new List<ConfigurationChangedEto>();
                }

                var eventIds = System.Text.Json.JsonSerializer.Deserialize<List<string>>(historyJson) ?? new List<string>();

                var events = new List<ConfigurationChangedEto>();
                var count = 0;

                // 按时间倒序获取事件
                foreach (var eventId in eventIds.OrderByDescending(id => id))
                {
                    if (count >= maxCount)
                    {
                        break;
                    }

                    var eventData = await GetEventByIdAsync(Guid.Parse(eventId));
                    if (eventData != null)
                    {
                        events.Add(eventData);
                        count++;
                    }
                }

                _logger.LogDebug("获取配置变更历史: Key: {Key}, Count: {Count}", key, events.Count);
                return events.OrderByDescending(e => e.EventTime).ToList();
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "获取配置变更历史失败: Key: {Key}", key);
                return new List<ConfigurationChangedEto>();
            }
        }

        public async Task<ConfigurationChangedEto?> GetEventByIdAsync(Guid eventId)
        {
            try
            {
                var cacheKey = GetEventCacheKey(eventId);
                var eventDataJson = await _distributedCache.GetStringAsync(cacheKey);

                if (string.IsNullOrEmpty(eventDataJson))
                {
                    return null;
                }

                var eventData = System.Text.Json.JsonSerializer.Deserialize<ConfigurationChangedEto>(eventDataJson);
                return eventData;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "根据ID获取事件失败: EventId: {EventId}", eventId);
                return null;
            }
        }

        public async Task<List<ConfigurationChangedEto>> GetEventsByTimeRangeAsync(
            DateTime startTime,
            DateTime endTime,
            Guid? tenantId = null)
        {
            try
            {
                // 简化实现：返回空列表
                // 实际应用中需要更高效的查询机制，可能需要数据库支持
                _logger.LogDebug("根据时间范围获取事件: StartTime: {StartTime}, EndTime: {EndTime} (简化实现)",
                    startTime, endTime);
                return new List<ConfigurationChangedEto>();
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "根据时间范围获取事件失败: StartTime: {StartTime}, EndTime: {EndTime}",
                    startTime, endTime);
                return new List<ConfigurationChangedEto>();
            }
        }

        public async Task CleanupExpiredEventsAsync(int retentionDays = 30)
        {
            try
            {
                // 简化实现：分布式缓存会自动清理过期的键
                // 这里可以添加额外的清理逻辑

                _logger.LogDebug("清理过期事件: RetentionDays: {RetentionDays}", retentionDays);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "清理过期事件失败: RetentionDays: {RetentionDays}", retentionDays);
            }
        }

        public async Task<EventStatistics> GetEventStatisticsAsync(Guid? tenantId = null)
        {
            try
            {
                var statsKey = GetStatisticsCacheKey(tenantId);
                var statsJson = await _distributedCache.GetStringAsync(statsKey);

                if (string.IsNullOrEmpty(statsJson))
                {
                    return new EventStatistics
                    {
                        LastUpdated = _clock.Now
                    };
                }

                var statistics = System.Text.Json.JsonSerializer.Deserialize<EventStatistics>(statsJson);
                return statistics ?? new EventStatistics { LastUpdated = _clock.Now };
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "获取事件统计信息失败: TenantId: {TenantId}", tenantId);
                return new EventStatistics { LastUpdated = _clock.Now };
            }
        }

        private async Task AddToHistoryAsync(ConfigurationChangedEto eventData)
        {
            try
            {
                var historyKey = GetHistoryCacheKey(eventData.Key, eventData.Namespace, eventData.TenantId);
                var historyJson = await _distributedCache.GetStringAsync(historyKey);

                List<string> eventIds;

                if (string.IsNullOrEmpty(historyJson))
                {
                    eventIds = new List<string>();
                }
                else
                {
                    eventIds = System.Text.Json.JsonSerializer.Deserialize<List<string>>(historyJson) ?? new List<string>();
                }

                // 添加事件ID到历史记录
                eventIds.Add(eventData.EventId.ToString("N"));

                // 限制历史记录数量
                if (eventIds.Count > 1000)
                {
                    eventIds = eventIds.Skip(eventIds.Count - 1000).ToList();
                }

                var updatedHistoryJson = System.Text.Json.JsonSerializer.Serialize(eventIds);
                var expiration = TimeSpan.FromDays(_options.Value.MaxEventRetentionDays);
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration };

                await _distributedCache.SetStringAsync(historyKey, updatedHistoryJson, options);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "添加到历史记录失败: EventId: {EventId}", eventData.EventId);
            }
        }

        private async Task UpdateStatisticsAsync(ConfigurationChangedEto eventData)
        {
            try
            {
                var statsKey = GetStatisticsCacheKey(eventData.TenantId);
                var statsJson = await _distributedCache.GetStringAsync(statsKey);

                EventStatistics statistics;

                if (string.IsNullOrEmpty(statsJson))
                {
                    statistics = new EventStatistics
                    {
                        EventsByImportance = new Dictionary<ConfigurationImportanceLevel, long>(),
                        EventsBySource = new Dictionary<ConfigurationChangeSource, long>(),
                        EventsByCategory = new Dictionary<string, long>()
                    };
                }
                else
                {
                    statistics = System.Text.Json.JsonSerializer.Deserialize<EventStatistics>(statsJson) ?? new EventStatistics();
                }

                // 更新统计信息
                statistics.TotalEvents++;

                if (eventData.EventTime.Date == _clock.Now.Date)
                {
                    statistics.TodayEvents++;
                }

                // 按重要性级别统计
                if (!statistics.EventsByImportance.ContainsKey(eventData.Importance))
                {
                    statistics.EventsByImportance[eventData.Importance] = 0;
                }
                statistics.EventsByImportance[eventData.Importance]++;

                // 按变更来源统计
                if (!statistics.EventsBySource.ContainsKey(eventData.ChangeSource))
                {
                    statistics.EventsBySource[eventData.ChangeSource] = 0;
                }
                statistics.EventsBySource[eventData.ChangeSource]++;

                // 按配置分类统计
                if (!string.IsNullOrEmpty(eventData.Category))
                {
                    if (!statistics.EventsByCategory.ContainsKey(eventData.Category))
                    {
                        statistics.EventsByCategory[eventData.Category] = 0;
                    }
                    statistics.EventsByCategory[eventData.Category]++;
                }

                statistics.LastUpdated = _clock.Now;

                var updatedStatsJson = System.Text.Json.JsonSerializer.Serialize(statistics);
                var expiration = TimeSpan.FromDays(7); // 统计信息保留7天
                var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration };

                await _distributedCache.SetStringAsync(statsKey, updatedStatsJson, options);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "更新统计信息失败: EventId: {EventId}", eventData.EventId);
            }
        }

        private static string GetEventCacheKey(Guid eventId)
        {
            return $"{EventPrefix}{eventId:N}";
        }

        private static string GetBatchEventCacheKey(Guid batchEventId)
        {
            return $"{BatchEventPrefix}{batchEventId:N}";
        }

        private static string GetHistoryCacheKey(string key, string @namespace, Guid? tenantId)
        {
            var tenantPart = tenantId?.ToString("N") ?? "global";
            var namespacePart = string.IsNullOrEmpty(@namespace) ? "default" : @namespace;
            return $"{HistoryPrefix}{tenantPart}:{namespacePart}:{key}";
        }

        private static string GetStatisticsCacheKey(Guid? tenantId)
        {
            var tenantPart = tenantId?.ToString("N") ?? "global";
            return $"{StatisticsPrefix}{tenantPart}";
        }
    }
}